﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace MipsMachine
{
	public class MipsDisassembler
	{
		public static string[] disassembleFile(string filename){
			uint[] data = ReadByteArrayFromFile(filename);
			string[] instructions = new string[data.Length];
			MipsInstruction[] ins = new MipsInstruction[data.Length];

			for (int i = 0; i < data.Length; i++) {
				ins[i] = new MipsInstruction(data[i]);
				//instructions[i] = ins[i].Type;
					instructions[i] = disassemble(ins[i]);
			}
			//foreach (string s in instructions)
			//	Console.WriteLine(s);
			return instructions;
		}

		public static string disassemble(uint code) {
			MipsInstruction ins = new MipsInstruction(code);
			return disassemble(ins);
		}

		public static string disassemble(MipsInstruction ins) {
			if (Enum.IsDefined(typeof(OpCode), ins.OpCode)){
				switch (ins.Type) {
					case InstructionType.IType:
						return IType(ins);
					case InstructionType.JType:
						return JType(ins);
					case InstructionType.RType:
						return RType(ins);
					default:
						return "Err";
				}

			}
			else return "...........";
		}

		private static string IType(MipsInstruction ins) {
			String opCode = ins.OpCode.ToString();
			String rt = ins.Rt.ToString();
			if (rt == "zero")
				rt = "" + 0;
			String rd = ins.Rd.ToString();
			if (rd == "zero")
				rd = "" + 0;
			String rs = ins.Rs.ToString();
			if (rs == "zero")
				rs = "" + 0;
			String imm = ins.GetSignedImmediate().ToString();
			//String imm = ins.Immediate.ToString();

			return opCode + " $" + rt + ", $" + rs + ", " + imm;
		}

		private static string JType(MipsInstruction ins) {
			String opCode = ins.OpCode.ToString();
			String address = ins.GetSignedImmediate().ToString();
			//String address = ins.Address.ToString();
			return opCode + " " + address;
		}

		private static string RType(MipsInstruction ins) {
			String opCode = ins.OpCode.ToString();
			if (ins.Funct == Function.SYSCALL) {
				return ins.Funct.ToString();
			}
			else if (ins.Funct == Function.JR) {
				String rt = ins.Rt.ToString();
				if (rt == "zero")
					rt = "" + 0;
				String funct = ins.Funct.ToString();
				return funct + " $" + rt;
			}
			else {
				String rt = ins.Rt.ToString();
				if (rt == "zero")
					rt = "" + 0;
				String rd = ins.Rd.ToString();
				if (rd == "zero")
					rd = "" + 0;
				String rs = ins.Rs.ToString();
				if (rs == "zero")
					rs = "" + 0;
				String shamt = ins.Shamt.ToString();
				Function f = ins.Funct;
				String funct = ins.Funct.ToString();
				if ((f == Function.SLL) || (f == Function.SRL) || (f == Function.SRA))
					return funct + " $" + rd + ", $" + rt + ", " + shamt;
				return funct + " $" + rd + ", $" + rs + ", $" + rt;
			}
		}

		public static uint[] ReadByteArrayFromFile(string fileName) {
			
			long length = (new FileInfo(fileName).Length) / 4;
			uint[] data = new uint[length];
			FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
			BinaryReader br = new BinaryReader(fs);

			

			for (int i = 0; i < length; i++) {
				data[i] = br.ReadUInt32();
			}

			return data;
		}
	}
}
